home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / pmake / prefix / sunrpc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-15  |  45.0 KB  |  1,561 lines

  1. /***********************************************************************
  2.  *
  3.  * PROJECT:      PMake
  4.  * MODULE:      Prefix -- Sun RPC Implementation
  5.  * FILE:      sunrpc.c
  6.  *
  7.  * AUTHOR:        Adam de Boor: Aug 23, 1989
  8.  *
  9.  * ROUTINES:
  10.  *    Name              Description
  11.  *    ----              -----------
  12.  *    SunRpc_ServerCreate Register a server for a <socket,prog,vers,proc>
  13.  *                        4-tuple
  14.  *    SunRpc_ServerDelete Unregister a server
  15.  *    SunRpc_Call         Issue a call to a Sun RPC procedure in another
  16.  *                        server.
  17.  *    SunRpc_MsgStream    Return stream over which call arrived
  18.  *    SunRpc_MsgProg        Return program called by message
  19.  *    SunRpc_MsgProc        Return procedure called by message
  20.  *    SunRpc_MsgVers        Return version desired by caller
  21.  *    SunRpc_MsgRawCred   Return raw credentials passed with message
  22.  *    SunRpc_MsgCred        Return converted credentials passed with
  23.  *                         message.
  24.  *
  25.  * REVISION HISTORY:
  26.  *    Date      Name        Description
  27.  *    ----      ----        -----------
  28.  *    8/23/89      ardeb        Initial version
  29.  *
  30.  * DESCRIPTION:
  31.  *    Implementation of the Sun RPC protocol (UDP transport) on top
  32.  *    of the customs RPC code.
  33.  *
  34.  *    This doesn't use the CLIENT and SVCXPRT things normally
  35.  *    associated with the Sun RPC -- just the XDR things.
  36.  *    
  37.  *    Note that this is not a complete implementation of the Sun RPC.
  38.  *    It is not intended as a standalone, as it uses functions in the
  39.  *    Sun RPC code, including a couple (_authenticate, _seterr_reply)
  40.  *    that are internal and undocumented. The reason for this thing's
  41.  *    existence is to allow the normal multi-threading and real call
  42.  *    caching for the Sun RPC servers, as well as to allow the use of
  43.  *    the explicit acknowledge for sockets serving Customs RPC.
  44.  *
  45.  *     Copyright (c) Berkeley Softworks 1989
  46.  *     Copyright (c) Adam de Boor 1989
  47.  *
  48.  *     Permission to use, copy, modify, and distribute this
  49.  *     software and its documentation for any non-commercial purpose
  50.  *    and without fee is hereby granted, provided that the above copyright
  51.  *     notice appears in all copies.  Neither Berkeley Softworks nor
  52.  *     Adam de Boor makes any representations about the suitability of this
  53.  *     software for any purpose.  It is provided "as is" without
  54.  *     express or implied warranty.
  55.  *
  56.  ***********************************************************************/
  57. #ifndef lint
  58. static char *rcsid =
  59. "$Id: sunrpc.c,v 1.3 89/10/10 00:38:33 adam Exp $";
  60. #endif lint
  61.  
  62. #include    <sys/time.h>
  63. #include    <sys/ioctl.h>
  64. #include    <sys/types.h>
  65. #include    <sys/socket.h>
  66. #include    <sys/file.h>
  67. #include    <rpc/rpc.h>
  68. #include    <rpc/pmap_prot.h>
  69. #include    <net/if.h>
  70. #include    <arpa/inet.h>
  71. #include    <sys/uio.h>
  72. #include    <errno.h>
  73. #include    <stdio.h>
  74. #include    <setjmp.h>
  75. #include    <sys/signal.h>
  76.  
  77. extern int  errno;
  78.  
  79. #define NO_RPC_STAT    /* Don't define customs RPC codes -- we use the
  80.              * Sun ones here */
  81. #include    "rpc.h"
  82. #include    "sunrpc.h"
  83.  
  84. /*
  85.  * Macro to deal with incompatible calling conventions between gcc and cc on
  86.  * a sparc (gcc passes the address in a register, since the structure is
  87.  * small enough, while cc still passes the address).
  88.  */
  89. #if defined(__GNUC__) && defined(sparc)
  90. #define InetNtoA(addr)    inet_ntoa(&(addr))
  91. #else
  92. #define InetNtoA(addr)    inet_ntoa(addr)
  93. #endif
  94.  
  95. #define SUN_MAX_DATA_SIZE   8192
  96. #define    RQCRED_SIZE    400        /* this size is excessive */
  97.  
  98.  
  99. #define SunRpcHash(id)            (((id) ^ (id >> 3) ^ (id >> 9)) & \
  100.                  (CACHE_THREADS-1))
  101.  
  102. /*
  103.  * RPC CACHE DEFINITIONS
  104.  */
  105. /*
  106.  * The cache is kept as a table of doubly-linked lists, hashed on the ID of the
  107.  * message, hanging from the SunRpcServer structure for the procedure call. The
  108.  * 'prev' pointer of the first entry in the chain points to the pointer in
  109.  * the table for that chain (i.e. *e->prev == e). Cache entries are flushed 10
  110.  * seconds after their last reference.
  111.  *
  112.  * A cache entry may be in one of two states: replied-to or reply-pending.
  113.  * If a call comes in that maps to an entry for which a reply is still
  114.  * pending, the call is dropped, as Sun RPC has no "I'm working on it"
  115.  * response as the PMake RPC does.
  116.  *
  117.  * If a call comes in that maps to an entry that has been replied-to, the
  118.  * reply is resent and the call dropped.
  119.  */
  120. typedef struct CacheLink {
  121.     struct SunCacheEntry    *next;
  122.     struct SunCacheEntry    *prev;
  123. } CacheLink;
  124.  
  125. typedef struct SunCacheEntry {
  126.     CacheLink            link;        /* Link in cache chain */
  127.     enum {
  128.     REPLY_PENDING,                    /* Service of call is in progress */
  129.     REPLY_SENT,                    /* Reply has been sent already */
  130.     }                  status;        /* Status of call */
  131.     unsigned long      id;         /* ID of call */
  132.     struct sockaddr_in    from;        /* Where call came from */
  133.     Rpc_Event          flushEvent; /* Event to flush cache entry */
  134.     enum clnt_stat      error;        /* If not RPC_SUCCESS, contains the
  135.                      * error code returned for the call */
  136.     Rpc_Opaque          replyData;  /* Data for reply */
  137.     struct rpc_msg      reply;        /* Reply message */
  138.     char                verf[MAX_AUTH_BYTES];    /* Room for verifier for
  139.                          * authentication */
  140. } SunCacheEntry;
  141.  
  142. #define CACHE_THREADS    8      /* The number of chains in each server
  143.                  * cache. NOTE: dependence on this value
  144.                  * in SunRpcHash() -- must be (2^n) */
  145. /*
  146.  * Structure describing an RPC server on a socket. The server is called
  147.  *
  148.  * enum clnt_stat
  149.  * serverProc(from, msg, argp, resp, datum, respPtr)
  150.  *    struct sockaddr_in *from;
  151.  *    Rpc_Message msg;
  152.  *    Rpc_Opaque  argp;
  153.  *    Rpc_Opaque  resp;
  154.  *    Rpc_Opaque  datum;
  155.  *    Rpc_Opaque  *respPtr;
  156.  *
  157.  * msg is a token that may be used to obtain other info about the call (see
  158.  * the SunRpc_Msg* functions).
  159.  *
  160.  * argp points to a buffer of the size indicated when the server was created
  161.  * into which the arguments were decoded (the buffer is initially zero-inited
  162.  * so the xdr function will allocate whatever memory is required). The
  163.  * arguments will be automatically freed when the call is complete.
  164.  *
  165.  * resp points to a buffer for the response of the size indicated when the
  166.  * server was created. The results will be encoded with the registered
  167.  * response procedure if the server procedure returns RPC_SUCCESS.
  168.  *
  169.  * respPtr points to the pointer to the results in the call cache -- the
  170.  * procedure can use it to store the correct address of the results should
  171.  * the passed size be insufficient (this can happen with things that return
  172.  * a variable-sized reply, especially since the data have to hang around until
  173.  * the entry is flushed from the cache).
  174.  *
  175.  * If the server procedure returns non-zero, it is taken to be an error code
  176.  * to be returned to the caller.
  177.  */
  178. typedef struct SunRpcServer {
  179.     struct SunRpcServer    *next;
  180.     unsigned long       prog;        /* Program being served */
  181.     unsigned long       vers;        /* Version of same */
  182.     unsigned long       proc;        /* Procedure being served */
  183.     xdrproc_t            argproc;    /* Procedure to decode arguments */
  184.     int                    argsize;    /* Size of arguments */
  185.     xdrproc_t            resproc;    /* Procedure to encode results */
  186.     int                    ressize;    /* Size of results */
  187.     enum clnt_stat        (*serverProc)();
  188.     Rpc_Opaque            datum;
  189.     CacheLink       cache[CACHE_THREADS];
  190. } SunRpcServer;
  191.  
  192. static SunRpcServer *sunRpcServers[FD_SETSIZE];
  193.  
  194. /*
  195.  * Message record from which we provide extra info for the called server
  196.  */
  197. typedef struct {
  198.     SunRpcServer        *server;
  199.     struct rpc_msg      *msg;
  200.     Rpc_Opaque            cred;
  201.     int                    stream;
  202. } SunRpcMessage;
  203.  
  204. /*
  205.  * Structure describing a pending call. The protocol-related structures are
  206.  * predefined, of course, but...
  207.  *
  208.  */
  209. typedef struct SunRpcCall {
  210.     struct SunRpcCall    *next;
  211.     unsigned long       id;         /* Copy of ID number of message */
  212.  
  213.     /*
  214.      * Information for receiving replies
  215.      */
  216.     enum clnt_stat      status;        /* Status of call */
  217.     struct sockaddr_in    remote;        /* Address of responder */
  218.     int                    replied;    /* Non-zero if reply received */
  219.     Rpc_Opaque            reply;        /* Place to store reply data */
  220.     xdrproc_t            resproc;    /* Procedure to decode response if
  221.                      * call succeeds */
  222.     AUTH                *auth;        /* Authenticator used in call */
  223.  
  224.     /*
  225.      * Information for issuing the call
  226.      */
  227.     int                    sock;        /* Socket over which to make the call */
  228.     struct msghdr       message;    /* Outgoing message */
  229.     int                    numRetries; /* Number of resends left */
  230.     Rpc_Event            resend;        /* Event used for resending */
  231. } SunRpcCall;
  232.  
  233. static SunRpcCall   *sunRpcCalls[FD_SETSIZE];
  234.  
  235.  
  236. /*
  237.  * Interval for flushing a call entry from the cache
  238.  */
  239. static struct timeval    flushTimeOut = {
  240.     10, 0
  241. };
  242. static int              sunRpcDebug = 0;    /* Non-zero to turn on debugging
  243.                          * output */
  244.  
  245. /***********************************************************************
  246.  *                SunRpcUniqueID
  247.  ***********************************************************************
  248.  * SYNOPSIS:        Return an unique identifier for a message.
  249.  *                Potential clashes between hosts are reduced by using
  250.  *                a random number on startup.
  251.  * CALLED BY:        SunRpc_Call
  252.  * RETURN:        The identifier
  253.  * SIDE EFFECTS:    None
  254.  *
  255.  * STRATEGY:
  256.  *
  257.  * REVISION HISTORY:
  258.  *    Name    Date        Description
  259.  *    ----    ----        -----------
  260.  *    ardeb    8/23/89        Initial Revision
  261.  *
  262.  ***********************************************************************/
  263. static unsigned long
  264. SunRpcUniqueID()
  265. {
  266.     static unsigned long  nextID = 0;
  267.  
  268.     if (nextID == 0) {
  269.     srandom(time(0) ^ getpid());
  270.     nextID = random();
  271.     } else {
  272.     nextID += 1;
  273.     }
  274.     return (nextID);
  275. }
  276.  
  277. /*-
  278.  *-----------------------------------------------------------------------
  279.  * SunRpcCacheFlushEntry --
  280.  *    Flush an entry from a server's cache when it hasn't been
  281.  *    referenced in a while.
  282.  *
  283.  * Results:
  284.  *    False -- no need to stay awake.
  285.  *
  286.  * Side Effects:
  287.  *    The SunCacheEntry structure is removed from the server's cache
  288.  *    and freed.
  289.  *
  290.  *-----------------------------------------------------------------------
  291.  */
  292. static Boolean
  293. SunRpcCacheFlushEntry(e, ev)
  294.     register SunCacheEntry  *e;     /* Entry to flush */
  295.     Rpc_Event              ev;     /* Event that caused this call */
  296. {
  297.     if (sunRpcDebug) {
  298.     printf("Flushing entry for %u\n", e->id);
  299.     }
  300.     
  301.     if ((e->flushEvent != ev) /* && sunRpcDebug */) {
  302.     printf("SunRpcCacheFlushEntry: flushEvent (%x) != ev (%x)\n",
  303.            e->flushEvent, ev);
  304.     }
  305.     Rpc_EventDelete(ev);
  306.     remque(&e->link);
  307.     if (e->replyData != (Rpc_Opaque)0) {
  308.     free((char *)e->replyData);
  309.     }
  310.     free((char *)e);
  311.  
  312.     return (False);
  313. }
  314.  
  315. /*-
  316.  *-----------------------------------------------------------------------
  317.  * SunRpcCacheDestroy --
  318.  *    Clean out the cache for a SunRpcServer.
  319.  *
  320.  * Results:
  321.  *    None.
  322.  *
  323.  * Side Effects:
  324.  *    Frees all memory and nukes all events associated with the cache
  325.  *    entries.
  326.  *
  327.  *-----------------------------------------------------------------------
  328.  */
  329. static void
  330. SunRpcCacheDestroy(s)
  331.     SunRpcServer      *s;    /* The server whose cache should be destroyed */
  332. {
  333.     register int          i;
  334.     register SunCacheEntry  *e;
  335.     
  336.     for (i = 0; i < CACHE_THREADS; i++) {
  337.     for (e = s->cache[i].next;
  338.          e != (SunCacheEntry *)&s->cache[i];
  339.          e = e->link.next)
  340.     {
  341.         if (e->replyData != (Rpc_Opaque)0) {
  342.         free((char *)e->replyData);
  343.         }
  344.         Rpc_EventDelete(e->flushEvent);
  345.         free((char *)e);    /* XXX */
  346.     }
  347.     }
  348. }
  349.  
  350. /*-
  351.  *-----------------------------------------------------------------------
  352.  * SunRpcCacheFind --
  353.  *    Find an RPC call in a server's cache. If it's not there and
  354.  *    create is True, the entry is created and *entryNewPtr is set
  355.  *    True. If the entry cannot be created, or doesn't exist and
  356.  *    create is False, NULL is returned.
  357.  *
  358.  * Results:
  359.  *    The SunCacheEntry for the call, or NULL if none.
  360.  *
  361.  * Side Effects:
  362.  *    A SunCacheEntry structure may be created and linked into the cache
  363.  *    for the server.
  364.  *
  365.  *-----------------------------------------------------------------------
  366.  */
  367. static SunCacheEntry *
  368. SunRpcCacheFind(server, from, id, create, entryNewPtr)
  369.     SunRpcServer      *server;        /* Server in whose cache the call
  370.                      * should be sought */
  371.     register struct sockaddr_in    *from;     /* Origin of the call */
  372.     unsigned long      id;             /* ID number of the call */
  373.     Boolean           create;            /* True if should create an entry
  374.                      * if we don't find it */
  375.     Boolean           *entryNewPtr;    /* Set True if a new entry was
  376.                      * created */
  377. {
  378.     register SunCacheEntry *e;
  379.     register int      chain;
  380.  
  381.     chain = SunRpcHash(id);
  382.     e = server->cache[chain].next;
  383.  
  384.     /*
  385.      * Look for existing cache entry.
  386.      */
  387.     if (sunRpcDebug) {
  388.     printf("SunRpcCacheFind: seeking %d@%s #%u...",
  389.            ntohs(from->sin_port),
  390.            InetNtoA(from->sin_addr),
  391.            id);
  392.     }
  393.     while (e != (SunCacheEntry *)&server->cache[chain]) {
  394.     if ((e->from.sin_addr.s_addr == from->sin_addr.s_addr) &&
  395.         (e->from.sin_port == from->sin_port) &&
  396.         (id == e->id))
  397.     {
  398.         break;
  399.     } else {
  400.         e = e->link.next;
  401.     }
  402.     }
  403.  
  404.     if (e == (SunCacheEntry *)&server->cache[chain]) {
  405.     if (create) {
  406.         /*
  407.          * Create new entry and link it at the head of its chain,
  408.          * setting *entryNewPtr as necessary.
  409.          */
  410.         if (sunRpcDebug) {
  411.         printf("creating new entry\n");
  412.         }
  413.         e = (SunCacheEntry *)malloc(sizeof(SunCacheEntry));
  414.         e->id =         id;
  415.         e->from =        *from;
  416.         e->status =     REPLY_PENDING;
  417.         e->flushEvent = Rpc_EventCreate(&flushTimeOut,
  418.                         SunRpcCacheFlushEntry,
  419.                         (Rpc_Opaque)e);
  420.         e->error =        RPC_SUCCESS;
  421.         e->replyData =  (Rpc_Opaque)0;
  422.  
  423.         insque(&e->link, &server->cache[chain]);
  424.  
  425.         if (entryNewPtr != (Boolean *)NULL) {
  426.         *entryNewPtr = True;
  427.         }
  428.     } else {
  429.         if (sunRpcDebug) {
  430.         printf("returning NULL\n");
  431.         }
  432.         return ((SunCacheEntry *)NULL);
  433.     }
  434.     } else if (entryNewPtr != (Boolean *)NULL) {
  435.     /*
  436.      * No new entry created -- mark *entryNewPtr false to indicate this
  437.      */
  438.     if (sunRpcDebug) {
  439.         printf("found it\n");
  440.     }
  441.     *entryNewPtr = False;
  442.     }
  443.     
  444.     /*
  445.      * The entry was referenced, so reset the flush timer for it.
  446.      */
  447.     Rpc_EventReset(e->flushEvent, &flushTimeOut);
  448.     return (e);
  449. }
  450.  
  451.  
  452. /***********************************************************************
  453.  *                SunRpcHandleStream
  454.  ***********************************************************************
  455.  * SYNOPSIS:        Deal with the readiness of a stream in which
  456.  *                we've registered interest.
  457.  * CALLED BY:        Rpc_Wait
  458.  * RETURN:        Nothing
  459.  * SIDE EFFECTS:    The packet is read from the socket.
  460.  *
  461.  * STRATEGY:
  462.  *    Because of the way the XDR routines for the RPC protocol are
  463.  *    set up, we have to go through a little bit of rigamarole before
  464.  *    we can actually decode the message. The trouble is, both
  465.  *    xdr_callmsg and xdr_replymsg expect to have the xdr routine for
  466.  *    the args/results, along with a pointer to them, stored in the
  467.  *    message so the routine can be called at the right point. We're
  468.  *    not like the Sun RPC, in that we don't know what kind of packet
  469.  *    might be arriving here, so we have to kludge the decision a bit.
  470.  *    Once we know what type of packet it is, we can do as the romans
  471.  *    do...sort of.
  472.  *
  473.  * REVISION HISTORY:
  474.  *    Name    Date        Description
  475.  *    ----    ----        -----------
  476.  *    ardeb    8/23/89        Initial Revision
  477.  *
  478.  ***********************************************************************/
  479. /*ARGSUSED*/
  480. static void
  481. SunRpcHandleStream(stream, data, what)
  482.     int            stream;        /* Stream that's ready */
  483.     Rpc_Opaque    data;        /* Data we stored (UNUSED) */
  484.     int            what;        /* For what it's ready (UNUSED) */
  485. {
  486.     struct sockaddr_in    remote;        /* Address of sender */
  487.     int                    remotelen;  /* Size of 'remote' (for recvfrom) */
  488.     unsigned char       buf[SUN_MAX_DATA_SIZE];
  489.     int                    msgLen;        /* Length of received datagram */
  490.     XDR                xdr;        /* XDR stream to 'buf' */
  491.     struct rpc_msg      msg;        /* Received message */
  492.     unsigned long    xid;        /* ID of same */
  493.     enum msg_type       direction;  /* Direction message is going */
  494.  
  495.     if (sunRpcDebug) {
  496.     printf("%d ready: ", stream);
  497.     }
  498.     
  499.     /*
  500.      * Keep trying to read the message as long as the recvfrom call is
  501.      * interrupted.
  502.      */
  503.     do {
  504.     remote.sin_addr.s_addr = 0;
  505.     remotelen = sizeof(remote);
  506.     msgLen = recvfrom(stream, buf, sizeof(buf), 0,
  507.               (struct sockaddr *)&remote, &remotelen);
  508.     } while ((msgLen < 0) && (errno == EINTR));
  509.  
  510.     /*
  511.      * Error-check results.
  512.      */
  513.     if (msgLen < 0) {
  514.     perror("recvfrom");
  515.     return;
  516.     }
  517.  
  518.     if (msgLen < 4 * sizeof(unsigned long)) {
  519.     if (sunRpcDebug) {
  520.         fprintf(stderr,
  521.             "SunRpcHandleStream: msgLen = %d (too short...)\n",
  522.             msgLen);
  523.     }
  524.     return;
  525.     }
  526.     
  527.     /*
  528.      * Set up a memory stream to decode the packet and for use in encoding
  529.      * things into buf once the packet has been dealt with.
  530.      */
  531.     xdrmem_create(&xdr, buf, sizeof(buf), XDR_DECODE);
  532.  
  533.     /*
  534.      * Fetch the message ID and direction so we know what to do.
  535.      */
  536.     XDR_GETLONG(&xdr, &xid);
  537.     xdr_enum(&xdr, &direction);
  538.     
  539.     switch(direction) {
  540.     case CALL:
  541.     {
  542.         SunRpcMessage   srpcmsg;    /* Message token for server */
  543.         SunRpcServer    *s;            /* Server found */
  544.         unsigned long   low,        /* Lowest version for program so far */
  545.                 high;       /* Highest version for prog so far */
  546.         enum accept_stat status;    /* Status to return. Set to
  547.                      * PROG_MISMATCH if a server for
  548.                      * the (prog,proc) pair is found,
  549.                      * but the version number is wrong */
  550.         int                slen;       /* Stream length for reply message */
  551.         /*
  552.          * Space for decoding credentials. Size comes from Sun RPC code.
  553.          */
  554.         char            cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
  555.  
  556.         /*
  557.          * Set up fields of call message required by decode.
  558.          */
  559.         msg.rm_call.cb_cred.oa_base = cred_area;
  560.         msg.rm_call.cb_verf.oa_base = &cred_area[MAX_AUTH_BYTES];
  561.  
  562.         XDR_SETPOS(&xdr, 0);
  563.         if (!xdr_callmsg(&xdr, &msg)) {
  564.         if (sunRpcDebug) {
  565.             fprintf(stderr, "Couldn't decode call message\n");
  566.         }
  567.         return;
  568.         }
  569.  
  570.         /*
  571.          * Locate a server for the call. At the end, s points to the
  572.          * proper server record, if any. If none, it will be NULL,
  573.          * status will be the proper return status and low & high will
  574.          * contain the range of program versions for the (prog,proc)
  575.          * requested, if any such version is available.
  576.          */
  577.         low = 0 - 1;
  578.         high = 0;
  579.  
  580.         status = PROG_UNAVAIL;
  581.         
  582.         for (s = sunRpcServers[stream]; s != NULL; s = s->next) {
  583.         if (s->prog == msg.rm_call.cb_prog) {
  584.             /*
  585.              * Switch to "procedure unavailable" if still on
  586.              * "program unavailable" since we've found *something*
  587.              * for the program.
  588.              */
  589.             if (status == PROG_UNAVAIL) {
  590.             status = PROC_UNAVAIL;
  591.             }
  592.  
  593.             if (s->proc == msg.rm_call.cb_proc) {
  594.             if (s->vers == msg.rm_call.cb_vers) {
  595.                 break;
  596.             } else {
  597.                 /*
  598.                  * Wrong version of (prog,proc) pair -- switch
  599.                  * from "procedure unavailable" error to
  600.                  * "version mismatch" error and keep track of
  601.                  * the version range that's available for return.
  602.                  */
  603.                 status = PROG_MISMATCH;
  604.                 if (s->vers < low) {
  605.                 low = s->vers;
  606.                 }
  607.                 if (s->vers > high) {
  608.                 high = s->vers;
  609.                 }
  610.             }
  611.             }
  612.         }
  613.         }
  614.  
  615.         if (s != NULL) {
  616.         /*
  617.          * Have a server -- see if the call was cached and enter it
  618.          * into the cache if not.
  619.          */
  620.         SunCacheEntry    *e;
  621.         Boolean            isNew;
  622.  
  623.         e = SunRpcCacheFind(s, &remote, xid, TRUE, &isNew);
  624.  
  625.         if (isNew) {
  626.             /*
  627.              * Brand-new call -- authenticate the message,
  628.              * allocate room for and decode the args,
  629.              * allocate room for the results and call out to the server
  630.              * procedure.
  631.              */
  632.             Rpc_Opaque        args;   /* Pointer to allocated args */
  633.             Rpc_Opaque        res;    /* Pointer to allocated results */
  634.             enum clnt_stat  stat;   /* Status to return */
  635.             struct svc_req  r;        /* "Request" for authentication */
  636.             SVCXPRT         xprt;   /* "Transport" for obtaining
  637.                          * verifier */
  638.             enum auth_stat  why;    /* Result of authentication */
  639.  
  640.             /*
  641.              * Set direction and ID of reply message.
  642.              */
  643.             e->reply.rm_xid = msg.rm_xid;
  644.             e->reply.rm_direction = REPLY;
  645.             
  646.             /*
  647.              * Set up request and attempt to authenticate the
  648.              * message.
  649.              */
  650.             xprt.xp_verf.oa_base = e->verf;
  651.             r.rq_xprt = &xprt;
  652.             r.rq_prog = msg.rm_call.cb_prog;
  653.             r.rq_vers = msg.rm_call.cb_vers;
  654.             r.rq_proc = msg.rm_call.cb_proc;
  655.             r.rq_cred = msg.rm_call.cb_cred;
  656.             r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
  657.  
  658.             why = _authenticate(&r, &msg);
  659.             if (why != AUTH_OK) {
  660.             e->reply.rm_reply.rp_stat = MSG_DENIED;
  661.             e->reply.rjcted_rply.rj_stat = AUTH_ERROR;
  662.             e->reply.rjcted_rply.rj_why = why;
  663.             } else {
  664.             /*
  665.              * Message has been accepted -- record that and the
  666.              * verifier returned by the authentication system.
  667.              */
  668.             e->reply.rm_reply.rp_stat = MSG_ACCEPTED;
  669.             e->reply.acpted_rply.ar_verf = xprt.xp_verf;
  670.             
  671. #ifdef MEM_TRACE
  672.             args = (Rpc_Opaque)calloc_tagged(s->argsize, 1, 1);
  673. #else
  674.             args = (Rpc_Opaque)calloc(s->argsize, 1);
  675. #endif
  676.             if (!(*s->argproc)(&xdr, args)) {
  677.                 /*
  678.                  * Couldn't decode the arguments -- choke
  679.                  */
  680.                 stat = RPC_CANTDECODEARGS;
  681.             } else {
  682.                 /*
  683.                  * Allocate and record reply data in cache entry.
  684.                  */
  685. #ifdef MEM_TRACE
  686.                 res = (Rpc_Opaque)calloc_tagged(s->ressize, 1, 2);
  687. #else
  688.                 res = (Rpc_Opaque)calloc(s->ressize, 1);
  689. #endif
  690.                 e->replyData = res;
  691.                 
  692.                 /*
  693.                  * Set up message token by which server can acquire
  694.                  * more info.
  695.                  */
  696.                 srpcmsg.server = s;
  697.                 srpcmsg.msg = &msg;
  698.                 srpcmsg.cred = r.rq_clntcred;
  699.                 srpcmsg.stream = stream;
  700.                 
  701.                 /*
  702.                  * Call out to the server. It should fill in resp
  703.                  * and return a status.
  704.                  */
  705.                 stat = (*s->serverProc)(&remote,
  706.                             (Rpc_Message)&srpcmsg,
  707.                             args,
  708.                             res,
  709.                             s->datum,
  710.                             &e->replyData);
  711.             }
  712.             
  713.             if (stat != RPC_SUCCESS) {
  714.                 /*
  715.                  * Failure -- encode clnt_stat into wire status.
  716.                  * This is pretty easy.
  717.                  */
  718.                 if (stat == RPC_AUTHERROR) {
  719.                 e->reply.rm_reply.rp_stat = MSG_DENIED;
  720.                 e->reply.rjcted_rply.rj_stat = AUTH_ERROR;
  721.                 e->reply.rjcted_rply.rj_why = AUTH_TOOWEAK;
  722.                 } else if (stat == RPC_CANTDECODEARGS) {
  723.                 e->reply.acpted_rply.ar_stat = GARBAGE_ARGS;
  724.                 } else {
  725.                 /*
  726.                  * Anything else is a "system error"
  727.                  */
  728.                 e->reply.acpted_rply.ar_stat = SYSTEM_ERR;
  729.                 }
  730.                 /*
  731.                  * Free the results, which are likely to be
  732.                  * garbage, and shouldn't be returned in any case.
  733.                  */
  734.                 free(e->replyData);
  735.                 e->replyData = NULL;
  736.             } else {
  737.                 /*
  738.                  * Set up the where and proc fields of the reply
  739.                  * message so the results get encoded properly.
  740.                  * Set the reply status to SUCCESS because we were.
  741.                  */
  742.                 e->reply.acpted_rply.ar_stat = SUCCESS;
  743.                 e->reply.acpted_rply.ar_results.proc = s->resproc;
  744.                 e->reply.acpted_rply.ar_results.where =
  745.                 e->replyData;
  746.             }
  747.  
  748.             /*
  749.              * Free up the arguments
  750.              */
  751.             if (stat != RPC_CANTDECODEARGS) {
  752.                 xdr.x_op = XDR_FREE;
  753.                 (* s->argproc) (&xdr, args);
  754.             }
  755.             free(args);
  756.  
  757.             /*
  758.              * If status is special "drop this" code, nuke
  759.              * the entry (so the resend will be handled -- the
  760.              * only thing this is used for so far is getting
  761.              * a mount request while trying to mount something,
  762.              * in which case we want the resend to get through)
  763.              * and return now.
  764.              */
  765.             if (stat == SUNRPC_DONTRESPOND) {
  766.                 SunRpcCacheFlushEntry(e, e->flushEvent);
  767.                 return;
  768.             }
  769.             }
  770.             
  771.             /*
  772.              * Pretend a reply has been sent so code below will
  773.              * actually "resend" the reply we've built.
  774.              */
  775.             e->status = REPLY_SENT;
  776.         }
  777.  
  778.         if (e->status == REPLY_SENT) {
  779.             /*
  780.              * A reply has been sent before (or needs to be). Put
  781.              * together a message from the rpc_msg and the
  782.              * reply data and ship the thing off to the caller.
  783.              */
  784.             xdr.x_op = XDR_ENCODE;
  785.             XDR_SETPOS(&xdr, 0);
  786.             if (!xdr_replymsg(&xdr, &e->reply)) {
  787.             return;
  788.             }
  789.         } else {
  790.             /*
  791.              * Pending replies can't be dealt with, since Sun RPC
  792.              * has no explicit acknowledge as Customs RPC does.
  793.              */
  794.             return;
  795.         }
  796.         } else {
  797.         /*
  798.          * Can't find server -- reply with whatever status we've
  799.          * determined is appropriate. First, we need to fetch
  800.          * a verifier for the credentials and authenticate the message.
  801.          *
  802.          * Note we can't do this above, as it relies on having a
  803.          * cache entry. Other possibility is to fake a cache entry.
  804.          */
  805.         struct svc_req  r;    /* "Request" for authentication */
  806.         SVCXPRT     xprt;   /* "Transport" for obtaining
  807.                      * verifier */
  808.         enum auth_stat  why;    /* Result of authentication */
  809.         char            verf[MAX_AUTH_BYTES];
  810.         struct rpc_msg    reply;
  811.  
  812.         /*
  813.          * Set up ID and direction of message
  814.          */
  815.         reply.rm_xid = msg.rm_xid;
  816.         reply.rm_direction = REPLY;
  817.  
  818.         /*
  819.          * Set up request and attempt to authenticate the
  820.          * message.
  821.          */
  822.         xprt.xp_verf.oa_base = verf;
  823.         r.rq_xprt = &xprt;
  824.         r.rq_prog = msg.rm_call.cb_prog;
  825.         r.rq_vers = msg.rm_call.cb_vers;
  826.         r.rq_proc = msg.rm_call.cb_proc;
  827.         r.rq_cred = msg.rm_call.cb_cred;
  828.         r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
  829.         
  830.         why = _authenticate(&r, &msg);
  831.         if (why != AUTH_OK) {
  832.             reply.rm_reply.rp_stat = MSG_DENIED;
  833.             reply.rjcted_rply.rj_stat = AUTH_ERROR;
  834.             reply.rjcted_rply.rj_why = why;
  835.         } else {
  836.             /*
  837.              * Message is kosher, but we still can't handle
  838.              * the request -- set up an accepted_reply with
  839.              * the status and verifier we've worked out.
  840.              */
  841.             reply.rm_reply.rp_stat = MSG_ACCEPTED;
  842.             reply.acpted_rply.ar_stat = status;
  843.             reply.acpted_rply.ar_verf = xprt.xp_verf;
  844.             if (status == PROG_MISMATCH) {
  845.             reply.acpted_rply.ar_vers.low = low;
  846.             reply.acpted_rply.ar_vers.high = high;
  847.             }
  848.         }
  849.         /*
  850.          * Encode the whole message into buf.
  851.          */
  852.         xdr.x_op = XDR_ENCODE;
  853.         XDR_SETPOS(&xdr, 0);
  854.         if (!xdr_replymsg(&xdr, &reply)) {
  855.             return;
  856.         }
  857.         }
  858.  
  859.         /*
  860.          * Buf now contains the message to be transmitted back to
  861.          * the caller.
  862.          */
  863.         slen = (int)XDR_GETPOS(&xdr);
  864.         
  865.         /*
  866.          * Try and send the datagram while we keep getting
  867.          * interrupted..
  868.          */
  869.         while ((sendto(stream, buf, slen, 0,
  870.                &remote, sizeof(remote)) != slen) &&
  871.            (errno == EINTR))
  872.         {
  873.         ;
  874.         }
  875.         break;
  876.     }
  877.     case REPLY:
  878.     {
  879.         /*
  880.          * Reset the stream to its start again and attempt to decode
  881.          * it as a reply.
  882.          */
  883.         SunRpcCall      *call,
  884.                 **prev;
  885.         struct rpc_err  err;
  886.         
  887.         
  888.         XDR_SETPOS(&xdr, 0);
  889.         bzero(&msg, sizeof(msg));
  890.         
  891.         /*
  892.          * Try and locate a call with the ID, since we need to store the
  893.          * proc and buffer location in the rpc_msg before calling
  894.          * xdr_replymsg...
  895.          */
  896.         
  897.         prev = &sunRpcCalls[stream];
  898.         for (call = sunRpcCalls[stream]; call != 0; call = call->next) {
  899.         if (xid == call->id) {
  900.             break;
  901.         } else {
  902.             prev = &call->next;
  903.         }
  904.         }
  905.         
  906.         if (call == (SunRpcCall *)0) {
  907.         if (sunRpcDebug) {
  908.             printf("unknown packet (no pending call of id %u)", xid);
  909.         }
  910.         return;
  911.         } else {
  912.         /*
  913.          * Set up to decode successful reply.
  914.          */
  915.         msg.acpted_rply.ar_results.where = call->reply;
  916.         msg.acpted_rply.ar_results.proc = call->resproc;
  917.         msg.acpted_rply.ar_verf = _null_auth;
  918.         
  919.         if (!xdr_replymsg(&xdr, &msg)) {
  920.             /*
  921.              * Nope -- no idea what it could be. Just discard the
  922.              * packet.
  923.              */
  924.             if (sunRpcDebug) {
  925.             fprintf(stderr, "Couldn't decode reply message");
  926.             }
  927.             return;
  928.         }
  929.         }
  930.         
  931.         if (sunRpcDebug) {
  932.         printf("Reply to %u: ", msg.rm_xid);
  933.         }
  934.         
  935.         /*
  936.          * Mark the call as replied, then figure out how successful we
  937.          * were.
  938.          */
  939.         call->replied = True;
  940.         
  941.         /*
  942.          * Decode wire result into more manageable error code, passing that
  943.          * back to caller.
  944.          */
  945.         _seterr_reply(&msg, &err);
  946.         call->status = err.re_status;
  947.         call->remote = remote;
  948.         
  949.         if (err.re_status == RPC_SUCCESS) {
  950.         /*
  951.          * Successful completion -- verify the responder is OK.
  952.          */
  953.         if (!AUTH_VALIDATE(call->auth, &msg.acpted_rply.ar_verf)) {
  954.             /*
  955.              * Nope -- return an authentication error.
  956.              */
  957.             call->status = RPC_AUTHERROR;
  958.         }
  959.         if(msg.acpted_rply.ar_verf.oa_base != NULL) {
  960.             /*
  961.              * Had credentials -- free any memory allocated for them
  962.              */
  963.             xdr.x_op = XDR_FREE;
  964.             (void)xdr_opaque_auth(&xdr, &msg.acpted_rply.ar_verf);
  965.         }
  966.         }
  967.         /*
  968.          * Unlink call from chain.
  969.          */
  970.         *prev = call->next;
  971.         break;
  972.     }
  973.     default:
  974.         if (sunRpcDebug) {
  975.         fprintf(stderr, "Unknown direction: %d\n", direction);
  976.         }
  977.         break;
  978.     }
  979.  
  980.     /*
  981.      * No need to destroy the stream, since it's all allocated locally.
  982.      */
  983. }
  984.  
  985.  
  986. /***********************************************************************
  987.  *                SunRpc_MsgStream
  988.  ***********************************************************************
  989.  * SYNOPSIS:        Return the stream over which a message arrived
  990.  * CALLED BY:        EXTERNAL
  991.  * RETURN:        The stream
  992.  * SIDE EFFECTS:    None
  993.  *
  994.  * STRATEGY:        None
  995.  *
  996.  * REVISION HISTORY:
  997.  *    Name    Date        Description
  998.  *    ----    ----        -----------
  999.  *    ardeb    8/23/89        Initial Revision
  1000.  *
  1001.  ***********************************************************************/
  1002. int
  1003. SunRpc_MsgStream(msg)
  1004.     Rpc_Message    msg;
  1005. {
  1006.     return ((SunRpcMessage *)msg)->stream;
  1007. }
  1008.  
  1009. /***********************************************************************
  1010.  *                SunRpc_MsgProg
  1011.  ***********************************************************************
  1012.  * SYNOPSIS:        Return the program for which message arrived
  1013.  * CALLED BY:        EXTERNAL
  1014.  * RETURN:        The program number
  1015.  * SIDE EFFECTS:    None
  1016.  *
  1017.  * STRATEGY:        None
  1018.  *
  1019.  * REVISION HISTORY:
  1020.  *    Name    Date        Description
  1021.  *    ----    ----        -----------
  1022.  *    ardeb    8/23/89        Initial Revision
  1023.  *
  1024.  ***********************************************************************/
  1025. unsigned long
  1026. SunRpc_MsgProg(msg)
  1027.     Rpc_Message    msg;
  1028. {
  1029.     return ((SunRpcMessage *)msg)->server->prog;
  1030. }
  1031.  
  1032. /***********************************************************************
  1033.  *                SunRpc_MsgVers
  1034.  ***********************************************************************
  1035.  * SYNOPSIS:        Return the version number for which message arrived
  1036.  * CALLED BY:        EXTERNAL
  1037.  * RETURN:        The version number
  1038.  * SIDE EFFECTS:    None
  1039.  *
  1040.  * STRATEGY:        None
  1041.  *
  1042.  * REVISION HISTORY:
  1043.  *    Name    Date        Description
  1044.  *    ----    ----        -----------
  1045.  *    ardeb    8/23/89        Initial Revision
  1046.  *
  1047.  ***********************************************************************/
  1048. unsigned long
  1049. SunRpc_MsgVers(msg)
  1050.     Rpc_Message    msg;
  1051. {
  1052.     return ((SunRpcMessage *)msg)->server->vers;
  1053. }
  1054.  
  1055. /***********************************************************************
  1056.  *                SunRpc_MsgProc
  1057.  ***********************************************************************
  1058.  * SYNOPSIS:        Return the procedure for which message arrived
  1059.  * CALLED BY:        EXTERNAL
  1060.  * RETURN:        The procedure number
  1061.  * SIDE EFFECTS:    None
  1062.  *
  1063.  * STRATEGY:        None
  1064.  *
  1065.  * REVISION HISTORY:
  1066.  *    Name    Date        Description
  1067.  *    ----    ----        -----------
  1068.  *    ardeb    8/23/89        Initial Revision
  1069.  *
  1070.  ***********************************************************************/
  1071. unsigned long
  1072. SunRpc_MsgProc(msg)
  1073.     Rpc_Message    msg;
  1074. {
  1075.     return ((SunRpcMessage *)msg)->server->proc;
  1076. }
  1077.  
  1078. /***********************************************************************
  1079.  *                SunRpc_MsgRawCred
  1080.  ***********************************************************************
  1081.  * SYNOPSIS:        Return the address of the raw credentials for the
  1082.  *                message
  1083.  * CALLED BY:        EXTERNAL
  1084.  * RETURN:        The raw credentials
  1085.  * SIDE EFFECTS:    None
  1086.  *
  1087.  * STRATEGY:        None
  1088.  *
  1089.  * REVISION HISTORY:
  1090.  *    Name    Date        Description
  1091.  *    ----    ----        -----------
  1092.  *    ardeb    8/23/89        Initial Revision
  1093.  *
  1094.  ***********************************************************************/
  1095. struct opaque_auth *
  1096. SunRpc_MsgRawCred(msg)
  1097.     Rpc_Message    msg;
  1098. {
  1099.     return &((SunRpcMessage *)msg)->msg->rm_call.cb_cred;
  1100. }
  1101.  
  1102. /***********************************************************************
  1103.  *                SunRpc_MsgCred
  1104.  ***********************************************************************
  1105.  * SYNOPSIS:        Return the processed credentials for the message
  1106.  * CALLED BY:        EXTERNAL
  1107.  * RETURN:        The processed credentials
  1108.  * SIDE EFFECTS:    None
  1109.  *
  1110.  * STRATEGY:        None
  1111.  *
  1112.  * REVISION HISTORY:
  1113.  *    Name    Date        Description
  1114.  *    ----    ----        -----------
  1115.  *    ardeb    8/23/89        Initial Revision
  1116.  *
  1117.  ***********************************************************************/
  1118. caddr_t
  1119. SunRpc_MsgCred(msg)
  1120.     Rpc_Message    msg;
  1121. {
  1122.     return ((SunRpcMessage *)msg)->cred;
  1123. }
  1124.  
  1125.  
  1126. /***********************************************************************
  1127.  *                SunRpcResend
  1128.  ***********************************************************************
  1129.  * SYNOPSIS:        Resend a registered call.
  1130.  * CALLED BY:        SunRpc_Call and Rpc_Wait (resend event)
  1131.  * RETURN:        TRUE if call timed out -- causes Rpc_Wait to return
  1132.  *                immediately rather than going to sleep.
  1133.  * SIDE EFFECTS:    call->replied will be set True on timeout
  1134.  *
  1135.  * STRATEGY:
  1136.  *
  1137.  * REVISION HISTORY:
  1138.  *    Name    Date        Description
  1139.  *    ----    ----        -----------
  1140.  *    ardeb    9/10/89        Initial Revision
  1141.  *
  1142.  ***********************************************************************/
  1143. static Boolean
  1144. SunRpcResend(call)
  1145.     SunRpcCall        *call;      /* Record for message to be sent */
  1146. {
  1147.     register SunRpcCall    *c;         /* Current call in list */
  1148.     register SunRpcCall    **prev;        /* Pointer to next field of previous call*/
  1149.     int                  numBytes;   /* Number of bytes in message */
  1150.     enum clnt_stat      status;        /* Status of call */
  1151.     
  1152.     if (!call->replied) {
  1153.     if (sunRpcDebug) {
  1154.         printf("Resending %u: ", call->id);
  1155.     }
  1156.     if (call->numRetries != 0) {
  1157.         call->numRetries -= 1;
  1158.         if (sunRpcDebug) {
  1159.         printf("%d left\n", call->numRetries);
  1160.         }
  1161.     send_again:
  1162.         do {
  1163.         numBytes = sendmsg (call->sock, &call->message, 0);
  1164.         } while ((numBytes < 0) && (errno == EINTR));
  1165.  
  1166.         if (numBytes < 0) {
  1167.         if (sunRpcDebug) {
  1168.             perror("RpcResend");
  1169.         }
  1170.         switch(errno) {
  1171.             case EMSGSIZE:
  1172.             status = RPC_CANTSEND;
  1173.             break;
  1174.             case ENOTCONN:
  1175.             /*
  1176.              * Socket is a disconnected TCP socket. Connect it to
  1177.              * the server to which this call is directed. XXX: This
  1178.              * connection is irreversible. If the connection
  1179.              * succeeds, resend the message.
  1180.              */
  1181.             if (connect(call->sock,
  1182.                     (struct sockaddr *)call->message.msg_name,
  1183.                     call->message.msg_namelen) == 0)
  1184.             {
  1185.                 goto send_again;
  1186.             } else {
  1187.                 if (sunRpcDebug) {
  1188.                 perror("connect");
  1189.                 }
  1190.             }
  1191.             /*FALLTHRU*/
  1192.             default:
  1193.             status = RPC_CANTSEND;
  1194.             break;
  1195.         }
  1196.         } else {
  1197.         status = RPC_SUCCESS;
  1198.         }
  1199.     } else {
  1200.         if (sunRpcDebug) {
  1201.         printf("TIMEOUT\n");
  1202.         }
  1203.         status = RPC_TIMEDOUT;
  1204.     }
  1205.     if (status != RPC_SUCCESS) {
  1206.         /*
  1207.          * If the resend was unsuccessful, mark the call as replied-to and
  1208.          * install the status as the response. Then remove the call from
  1209.          * the list of calls pending for the socket and tell Rpc_Wait not
  1210.          * to go to sleep so the message sender can be woken up as soon as
  1211.          * possible
  1212.          */
  1213.         call->replied = True;
  1214.         call->status = status;
  1215.         
  1216.         prev = &sunRpcCalls[call->sock];
  1217.         for (c = sunRpcCalls[call->sock]; c != 0; c = c->next) {
  1218.         if (c == call) {
  1219.             break;
  1220.         } else {
  1221.             prev = &c->next;
  1222.         }
  1223.         }
  1224.         if (c != 0) {
  1225.         *prev = c->next;
  1226.         }
  1227.         return (True);
  1228.     } else {
  1229.         /*
  1230.          * Tell Rpc_Wait it's ok to go to sleep, if it wants to. Nothing
  1231.          * interesting will happen for this call until a response comes
  1232.          * back.
  1233.          */
  1234.         return (False);
  1235.     }
  1236.     } else {
  1237.     /*
  1238.      * If the message has already been replied-to, we don't want to
  1239.      * go to sleep. Rather, Rpc_Wait should return to its caller so
  1240.      * the message may be processed as quickly as possible.
  1241.      */
  1242.     if(sunRpcDebug) {
  1243.         printf("Resend on replied-to message %u\n", call->id);
  1244.     }
  1245.     return(True);
  1246.     }
  1247. }
  1248.  
  1249. /***********************************************************************
  1250.  *                SunRpc_Call
  1251.  ***********************************************************************
  1252.  * SYNOPSIS:        Perform a call to a remote service
  1253.  * CALLED BY:        EXTERNAL and recursive (if no port given for call)
  1254.  * RETURN:        status of call
  1255.  * SIDE EFFECTS:    ?
  1256.  *
  1257.  * STRATEGY:
  1258.  *
  1259.  * REVISION HISTORY:
  1260.  *    Name    Date        Description
  1261.  *    ----    ----        -----------
  1262.  *    ardeb    9/10/89        Initial Revision
  1263.  *
  1264.  ***********************************************************************/
  1265. enum clnt_stat
  1266. SunRpc_Call(sock, server, auth, progNum, procNum, versNum, inProc, inData,
  1267.         outProc, outData, numRetries, retry)
  1268.     int                    sock;       /* Socket on which to call */
  1269.     struct sockaddr_in    *server;    /* Location of server. If port is 0,
  1270.                      * we will contact port mapper to find
  1271.                      * the proper port */
  1272.     AUTH                *auth;        /* Credentials for call */
  1273.     int                    progNum;    /* Program to call */
  1274.     int                    procNum;    /* Procedure within same */
  1275.     int                    versNum;    /* Versionof same */
  1276.     xdrproc_t            inProc;        /* Procedure to encode args */
  1277.     caddr_t             inData;        /* Data to pass */
  1278.     xdrproc_t            outProc;    /* Procedure to decode results */
  1279.     caddr_t             outData;    /* Place to store results */
  1280.     int                    numRetries; /* Number of times to retry call */
  1281.     struct timeval      *retry;        /* Interval between retries */
  1282. {
  1283.     SunRpcCall            call;        /* Call descriptor for Resend and
  1284.                      * HandleStream */
  1285.     struct iovec        iov[1];        /* Vector for sendmsg */
  1286.     struct rpc_msg        message;    /* Message to be sent */
  1287.     char                msgbuf[SUN_MAX_DATA_SIZE];
  1288.     XDR                    xdr;        /* Stream for encoding message into
  1289.                      * msgbuf */
  1290.     int                    nrefreshes; /* Number of times to refresh old
  1291.                      * credentials */
  1292.  
  1293.     if (server->sin_port == 0) {
  1294.     struct sockaddr_in  pmap;   /* Address of portmapper */
  1295.     unsigned short        port;   /* Value returned by same */
  1296.     struct pmap         arg;    /* Args to GETPORT call */
  1297.     struct timeval        timeout;/* Resend interval */
  1298.     enum clnt_stat         result; /* Result of call */
  1299.  
  1300.     /*
  1301.      * Set up address of portmapper on server's machine
  1302.      */
  1303.     pmap.sin_family = AF_INET;
  1304.     pmap.sin_port = htons(PMAPPORT);
  1305.     pmap.sin_addr = server->sin_addr;
  1306.     /*
  1307.      * Set up parameters for query of remote side.
  1308.      * XXX: always looks for UDP mapping.
  1309.      */
  1310.     arg.pm_prog = progNum;
  1311.     arg.pm_vers = versNum;
  1312.     arg.pm_prot = IPPROTO_UDP;
  1313.     arg.pm_port = 0;            /* Not needed or used, but init anyway */
  1314.     /*
  1315.      * Resend at 2.5 second interval
  1316.      */
  1317.     timeout.tv_sec = 2;
  1318.     timeout.tv_usec = 500000;
  1319.  
  1320.     /*
  1321.      * Recurse to issue call to portmapper
  1322.      */
  1323.     result = SunRpc_Call(sock, &pmap, authnone_create(),
  1324.                  PMAPPROG, PMAPPROC_GETPORT, PMAPVERS,
  1325.                  xdr_pmap, &arg, xdr_u_short, &port,
  1326.                  3, &timeout);
  1327.     if (result != RPC_SUCCESS) {
  1328.         return(result);
  1329.     } else if (port == 0) {
  1330.         /*
  1331.          * If not registered, return PROGUNAVAIL error
  1332.          */
  1333.         return (RPC_PROGUNAVAIL);
  1334.     }
  1335.     /*
  1336.      * Set port in passed address, both for now and later.
  1337.      */
  1338.     server->sin_port = htons(port);
  1339.     }
  1340.  
  1341.     /*
  1342.      * Set up the message for sendmsg first
  1343.      */
  1344.     call.message.msg_name =         (caddr_t)server;
  1345.     call.message.msg_namelen =        sizeof(*server);
  1346.     call.message.msg_iov =          iov;
  1347.     call.message.msg_iovlen =        1;
  1348.     call.message.msg_accrights =    (caddr_t)0;
  1349.     call.message.msg_accrightslen = 0;
  1350.  
  1351.     /*
  1352.      * Set up the constant portion of the call record.
  1353.      */
  1354.     call.sock =                        sock;
  1355.     call.numRetries =            numRetries;
  1356.     call.reply =                    (Rpc_Opaque)outData;
  1357.     call.resproc =            outProc;
  1358.     call.auth =                        auth;
  1359.     call.resend =                   Rpc_EventCreate(retry,
  1360.                             SunRpcResend,
  1361.                             (Rpc_Opaque)&call);
  1362.  
  1363.     message.rm_direction =        CALL;
  1364.     message.rm_call.cb_rpcvers=     RPC_MSG_VERSION;
  1365.     message.rm_call.cb_prog =       progNum;
  1366.     message.rm_call.cb_vers =       versNum;
  1367.     message.rm_call.cb_proc =       procNum;
  1368.     
  1369.     /*
  1370.      * Open an XDR memory stream to encode the call into msgbuf. The io vector
  1371.      * gets pointed at msgbuf as well -- the length will be set once things
  1372.      * are encoded.
  1373.      */
  1374.     xdrmem_create(&xdr, msgbuf, sizeof(msgbuf), XDR_ENCODE);
  1375.     iov[0].iov_base = msgbuf;
  1376.  
  1377.     for (nrefreshes = 2; nrefreshes > 0; nrefreshes -= 1) {
  1378.     /*
  1379.      * Set the ID and link the call into the list of calls for the socket.
  1380.      * The 'replied' field gets set False so we know when a reply has
  1381.      * come in or the call has timed out.
  1382.      */
  1383.     message.rm_xid = call.id = SunRpcUniqueID();
  1384.     call.replied =         False;
  1385.     call.next =           sunRpcCalls[sock];
  1386.     sunRpcCalls[sock] =       &call;
  1387.  
  1388.     /*
  1389.      * Encode the header, procedure number, credentials and arguments
  1390.      * into the msgbuf buffer.
  1391.      */
  1392.     if (!xdr_callhdr(&xdr, &message) ||
  1393.         ! XDR_PUTLONG(&xdr, &message.rm_call.cb_proc) ||
  1394.         ! AUTH_MARSHALL(auth, &xdr) ||
  1395.         ! (*inProc)(&xdr, inData))
  1396.     {
  1397.         /*
  1398.          * Remove the call from the call chain by hand and set the status
  1399.          * to be CANTENCODEARGS, then break out to finish up other
  1400.          * cleanup.
  1401.          */
  1402.         sunRpcCalls[sock] = call.next;
  1403.         call.status = RPC_CANTENCODEARGS;
  1404.         break;
  1405.     }
  1406.     /*
  1407.      * Record size of message in the io vector.
  1408.      */
  1409.     iov[0].iov_len = XDR_GETPOS(&xdr);
  1410.  
  1411.     /*
  1412.      * Pay attention to the socket if wasn't doing so before, then call
  1413.      * SunRpcResend to send the initial call.
  1414.      */
  1415.     Rpc_Watch(sock, RPC_READABLE, SunRpcHandleStream, (Rpc_Opaque)0);
  1416.     (void)SunRpcResend(&call);
  1417.  
  1418.     /*
  1419.      * Wait for some sort of reply
  1420.      */
  1421.     while (!call.replied) {
  1422.         Rpc_Wait();
  1423.     }
  1424.  
  1425.     /*
  1426.      * If no-one else interested in the socket, ignore it.
  1427.      */
  1428.     if ((sunRpcCalls[sock] == 0) && (sunRpcServers[sock] == 0)) {
  1429.         Rpc_Ignore(sock);
  1430.     }
  1431.     
  1432.     /*
  1433.      * The only time we loop is if (1) the call failed due to bad
  1434.      * authentication and (2) AUTH_REFRESH indicates there was something
  1435.      * that could be done (i.e. our credentials might have been stale.
  1436.      */
  1437.     if ((call.status != RPC_AUTHERROR) || !AUTH_REFRESH(auth)) {
  1438.         break;
  1439.     }
  1440.     }
  1441.  
  1442.     /*
  1443.      * Now we know we're done, nuke the resend event.
  1444.      */
  1445.     Rpc_EventDelete(call.resend);
  1446.  
  1447.     /*
  1448.      * Return the status we got from the other side.
  1449.      */
  1450.     return(call.status);
  1451. }
  1452.  
  1453.  
  1454.  
  1455. /***********************************************************************
  1456.  *                SunRpc_ServerCreate
  1457.  ***********************************************************************
  1458.  * SYNOPSIS:        Bind a procedure to a <program,version,procedure,socket>
  1459.  *                tuple.
  1460.  * CALLED BY:        EXTERNAL
  1461.  * RETURN:        Nothing.
  1462.  * SIDE EFFECTS:    A SunRpcServer record is created and the socket's
  1463.  *                handling procedure is set to SunRpcHandleStream,
  1464.  *                nuking any previous handler.
  1465.  *
  1466.  * STRATEGY:
  1467.  *
  1468.  * REVISION HISTORY:
  1469.  *    Name    Date        Description
  1470.  *    ----    ----        -----------
  1471.  *    ardeb    9/10/89        Initial Revision
  1472.  *
  1473.  ***********************************************************************/
  1474. void
  1475. SunRpc_ServerCreate(sock, progNum, procNum, versNum, proc, data,
  1476.             argSize, argProc, resSize, resProc)
  1477.     int                sock;    /* Socket over which calls will come */
  1478.     unsigned long   progNum;    /* Program number to serve */
  1479.     unsigned long   procNum;    /* Procedure number in same */
  1480.     unsigned long   versNum;    /* Version of same */
  1481.     enum clnt_stat  (*proc)();    /* Procedure to call */
  1482.     Rpc_Opaque        data;       /* Data to pass it */
  1483.     int                argSize;    /* Space to allocate for args */
  1484.     xdrproc_t        argProc;    /* Argument decode procedure */
  1485.     int                resSize;    /* Space to allocate for results */
  1486.     xdrproc_t        resProc;    /* Results encode procedure */
  1487. {
  1488.     SunRpcServer    *server;
  1489.     CacheLink        *c;
  1490.     int                i;
  1491.  
  1492.     server = (SunRpcServer *)malloc(sizeof(SunRpcServer));
  1493.     server->prog        = progNum;
  1494.     server->proc        = procNum;
  1495.     server->vers        = versNum;
  1496.     server->argproc     = argProc;
  1497.     server->argsize     = argSize;
  1498.     server->resproc     = resProc;
  1499.     server->ressize     = resSize;
  1500.     server->serverProc    = proc;
  1501.     server->datum       = data;
  1502.     server->next        = sunRpcServers[sock];
  1503.     sunRpcServers[sock]    = server;
  1504.  
  1505.     /*
  1506.      * Initialize cache links to point to themselves.
  1507.      */
  1508.     for (i = CACHE_THREADS, c = server->cache; i > 0; i--, c++) {
  1509.     c->next = c->prev = (struct SunCacheEntry *)c;
  1510.     }
  1511.  
  1512.     Rpc_Watch(sock, RPC_READABLE, SunRpcHandleStream, (Rpc_Opaque)0);
  1513. }
  1514.  
  1515. /***********************************************************************
  1516.  *                SunRpc_ServerDelete
  1517.  ***********************************************************************
  1518.  * SYNOPSIS:        Remove a binding to a procedure.
  1519.  * CALLED BY:        EXTERNAL
  1520.  * RETURN:        Nothing
  1521.  * SIDE EFFECTS:    If no servers or calls left on the socket, the
  1522.  *                socket is ignored.
  1523.  *
  1524.  * STRATEGY:
  1525.  *
  1526.  * REVISION HISTORY:
  1527.  *    Name    Date        Description
  1528.  *    ----    ----        -----------
  1529.  *    ardeb    9/10/89        Initial Revision
  1530.  *
  1531.  ***********************************************************************/
  1532. void
  1533. SunRpc_ServerDelete(sock, progNum, procNum, versNum)
  1534.     int                sock;    /* Socket over which calls will come */
  1535.     unsigned long   progNum;    /* Program number to serve */
  1536.     unsigned long   procNum;    /* Procedure number in same */
  1537.     unsigned long   versNum;    /* Version of same */
  1538. {
  1539.     SunRpcServer    *s, **prev;
  1540.  
  1541.     prev = &sunRpcServers[sock];
  1542.  
  1543.     for (s = *prev; s != 0; s = *prev) {
  1544.     if ((s->prog==progNum) && (s->proc==procNum) && (s->vers==versNum)) {
  1545.         break;
  1546.     } else {
  1547.         prev = &s->next;
  1548.     }
  1549.     }
  1550.     if (s) {
  1551.     *prev = s->next;
  1552.  
  1553.     SunRpcCacheDestroy(s);
  1554.     free((char *)s);
  1555.     }
  1556.  
  1557.     if (sunRpcServers[sock] == 0 && sunRpcCalls[sock] == 0) {
  1558.     Rpc_Ignore(sock);
  1559.     }
  1560. }
  1561.